/***********************************************************
 * Author: 	Brandon McKune
 * E-Mail:	bmckune.cs@gmail.com
 * Date:	September 2, 2011
 * Class:	Advanced OS
 * Time:	1150 - 1325
 * Smstr:	Fall 2011
 */

#include "includes.h"
#include "ClTask.h"
#include "ClTaskGenerator.h"
#include "ClRTClock.h"
#include "ClRandomizer.h"
#include "Utilities.cpp"
#include "ClScheduler.h"

#define SUCCESSFUL_EXEC 	0

//UNIT_TEST_CODE procedures
//To test, these need to be called in order to insure
//that objects that use other previously test objects
//are tested correctly.
void testClRTClock(uint32_t iterations);
void testClTask(uint32_t iterations, uint64_t procSpeed);
void testClRandomizer();
void testUtilities();
void testClTaskGenerator(uint32_t iterations, uint32_t numTasks);
void testClScheduler(uint16_t testCase);

#define NUM_TASK	8 - systemLoad*2

int main(int argv, char** argc){
	cout << "Master initiation..." << endl;

#ifdef _TESTING
	testClRTClock(10);
	testClTask(1, 1000000);
	testClRandomizer();
	testUtilities();
	testClTaskGenerator(10, 5);
	testClScheduler(0);

	exit(0);
#endif

	if(argv != 3){
		cerr << "Please input a value for system load {2 = light, 1 = medium, 0 = heavy}" << endl;
		cerr << "and an input for the scheduler {0 = BASE, 1 = INTERMEDIATE, 2 = FULL}." << endl;
		exit(1);
	}

	int32_t systemLoad = atoi(argc[1]);
	if(-1 < systemLoad && systemLoad > 2){
		cerr << "Invalid system load value; {0-2} expected, "
							<< systemLoad << " returned." << endl;
		exit(1);
	}

	//Adjust system load
	systemLoad += 1;

#ifdef _DEBUG
	cout << "System Load: " << systemLoad;
#endif

	int32_t scheduler = atoi(argc[2]);
	if(-1 < scheduler && scheduler > 2){
		cerr << "Invalid scheduler value; {0-2} expected, "
							<< scheduler << " returned." << endl;
		exit(1);
	}
#ifdef _DEBUG
	cout << " Scheduler: " << scheduler << endl;
#endif

	ClTaskGenerator *ptr_taskGen = ClTaskGenerator::getInstance();

	ClRTClock *ptr_rtClock = ClRTClock::getInstance();

	ClScheduler *ptr_Scheduler = ClScheduler::getInstance();
	ptr_Scheduler->setupScheduler(g_numProcessors, g_ProcessorSpeed);

	vector<ClTask> interruptVector;

	const uint32_t MAX_CLOCK_TIME = 1000;

	//Loop until the maximum allowed amount of time for recieving aperiod tasks
	while(ptr_rtClock->getTimeInterval() < MAX_CLOCK_TIME){
		//Check for interrupts
		interruptVector = ptr_taskGen->generateTasks(NUM_TASK);
		//Run scheduling interval
		ptr_Scheduler->runScheduler((ClScheduler::EnumSchedulerType)scheduler, &interruptVector);
		//advance the clock
		ptr_rtClock->tick();
	}

	//Continue looping with task interrupts disabled to clear
	//ready queue.
	while(ptr_Scheduler->hasTasksWaiting()){
		//Run scheduling interval
		ptr_Scheduler->runScheduler((ClScheduler::EnumSchedulerType)scheduler, &interruptVector);
		//Advance the clock
		ptr_rtClock->tick();
	}

	//Print the finish queue to standard out to capture
	ptr_Scheduler->printFinishedQueue();

#ifdef _DEBUG
	ptr_Scheduler->printReadyQueue();
	ptr_Scheduler->printRunningQueue();
#endif
	return SUCCESSFUL_EXEC;
}

/**
 * UNIT_TEST_CODE
 * testClRTClock:
 * Description:
 * 		This function tests the ClRTClock class code base
 * 		with multiple mechanisms of access to the singleton
 * 		object that is created.
 * Parameters:
 * 		uint32_t iterations
 * 			The number of times you want to loop and test
 * 			the functions.
 * Return:
 * 		N/A
 */
void testClRTClock(uint32_t iterations){
	cout << "Unit Testing the ClRTClock" << endl;

	ClRTClock *ptr = NULL;
	ptr = ClRTClock::getInstance();

	for(uint32_t i = 0; i < iterations; i++){
		ptr->tick();
		cout << "Clock Time: " << ptr->getTimeInterval() << endl;

		if(i % 5 == 0){
			cout << "Testing clock: ";
			cout << ClRTClock::getInstance()->getTimeInterval() << endl;
		}
	}
}

/**
 * UNIT_TEST_CODE
 * testClTask:
 * Description:
 * 		This function tests the ClTask class code base.  This class
 * 		uses the ClRTClock singleton.
 * Parameters:
 * 		uint32_t iterations
 * 			The number of times you want to loop and test
 * 			the functions.
 * 		uint64_t procSpeed
 * 			The processor speed in which to record within
 * 			the task created.
 * Return:
 * 		N/A
 */
void testClTask(uint32_t iterations, uint64_t procSpeed){
	cout << "Unit Testing the Cltask" << endl;

	for(uint32_t i = 0; i < iterations; i++){
		ClTask *task = NULL;
		task = new ClTask();

		task->randomize(procSpeed);
		//Tests all the getter procedures
		task->printTaskInternals();

		//Test the setters
		task->setMaxProcSpeedHz(procSpeed + (i+1));
		task->setArrivalTime(i + 1);
		task->setFinishedTime(task->getDeadline() + procSpeed);
		task->setProcessedRateHz(i + 1);

		task->printTaskInternals();
		delete(task);
	}
}

/**
 * UNIT_TEST_CODE
 * testClRandomizer:
 * Description:
 * 		This function tests the ClRandomizer class code base.  This class
 * 		uses the random number generator from /dev/random
 * Parameters:
 * 		uint32_t iterations
 * 			The number of times you want to loop and test
 * 			the functions.
 * Return:
 * 		N/A
 */
void testClRandomizer(){
	cout << "Unit Testing the ClRandomizer" << endl;
	ClRandomizer *ptr = NULL;
	ptr = ClRandomizer::getInstance();

	for(uint32_t i = 0; i < 5; i++){
		cout << "Random from ptr: " << ptr->getRandomNum() << endl;
		cout << "Random from getInstance(): "
				<< ClRandomizer::getInstance()->getRandomNum() << endl;
	}
}

/**
 * UNIT_TEST_CODE
 * testUtilties:
 * Description:
 * 		This function tests the Utilities class code base
 * 		that is created.
 * Parameters:
 * 		uint32_t iterations
 * 			The number of times you want to loop and test
 * 			the functions.
 * Return:
 * 		N/A
 */
void testUtilities(){
	cout << "Unit testing the Utilities" << endl;
	vector<ClTask> *test = new vector<ClTask>();
	test->clear();

	for(int i = 0; i < 2; i++){
		ClTask *temp = new ClTask();
		temp->randomize(1000000);
		test->push_back(*temp);
		delete(temp);
	}

	PrintVector(test);
	CleanUpVector(test);
}

/**
 * UNIT_TEST_CODE
 * testClTaskGenerator:
 * Description:
 * 		This function tests the ClTaskGenerator class code base
 * 		with multiple mechanisms of access to the singleton
 * 		object that is created.
 * Parameters:
 * 		uint32_t iterations
 * 			The number of times you want to loop and test
 * 			the functions.
 * Return:
 * 		N/A
 */
void testClTaskGenerator(uint32_t iterations, uint32_t numTasks){
	cout << "Unit Testing the ClTaskGenerator" << endl;

	ClTaskGenerator *ptr = NULL;
	vector<ClTask> vec;

	ptr = ClTaskGenerator::getInstance();

	for(uint32_t i = 0; i < iterations; i++){
		ClRTClock::getInstance()->tick();
		cout << "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<" << endl;
		vec = ptr->generateTasks(numTasks);
		if(!vec.empty()){
			PrintVector(&vec);
			CleanUpVector(&vec);
		}
		vec = ClTaskGenerator::getInstance()->generateTasks(numTasks);
		if(!vec.empty()){
			PrintVector(&vec);
			CleanUpVector(&vec);
		}
	}
}

/**
 *	UNIT_TEST_CODE
 * 	testClScheduler Function:
 * 	Description:
 * 		This function is used to test every possible function created
 * 		within scheduler.  This test case never made it to completion
 * 		due to an unknown memory corruption error that was random.
 * 	Parameters:
 * 	Return:
 * 		void
 */
void testClScheduler(uint16_t testCase){
	ClScheduler *ptr = NULL;
	ptr = ClScheduler::getInstance();
	ptr->setupScheduler(8, 1000000000);

	vector<ClTask> *interrupts = new vector<ClTask>();
	interrupts->clear();

	for(int j = 0; j < 4; j++){
		for(int i = 0; i < 2; i++){
			ClTask tempTask;
			tempTask.randomize(i);
			interrupts->push_back(tempTask);
		}

		ptr->processInterrupts(interrupts);
	}

	ptr->printReadyQueue();
}
